package com.sikulifang.bank.simulation.service.bank;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.db.Entity;
import cn.hutool.db.Page;
import cn.hutool.db.PageResult;
import cn.hutool.db.sql.SqlBuilder;
import com.sikulifang.bank.simulation.constant.CodeConstants;
import com.sikulifang.bank.simulation.dto.QueryReceiptDTO;
import com.sikulifang.bank.simulation.dto.ReceiptDTO;
import com.sikulifang.bank.simulation.dto.ResponseReceiptDTO;
import com.sikulifang.bank.simulation.dto.TransferPaymentDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticB2bPayDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticB2bPayQueryDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticB2cPayDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticB2cPayQueryDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticDowReceiptDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticPayRollDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticPayRollQueryDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticQueryBalanceDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticQueryDetailDTO;
import com.sikulifang.bank.simulation.dto.citic.CiticQueryReceiptInfoDTO;
import com.sikulifang.bank.simulation.enums.BankEnum;
import com.sikulifang.bank.simulation.util.DataUtil;
import com.sikulifang.bank.simulation.util.PdfUtil;
import com.sikulifang.bank.simulation.util.R;
import com.sikulifang.frequency.core.InterfaceTypeEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;

import javax.xml.xpath.XPathConstants;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.sikulifang.bank.simulation.constant.CiticConstants.DLBALQRY;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLCIDBST;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLCIDSTT;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLEDCDTD;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLEDDRSQ;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLINTTRN;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLSALDET;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLSALIMP;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLTRNALL;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLUPRDET;
import static com.sikulifang.bank.simulation.constant.CiticConstants.DLUPRSUB;
import static com.sikulifang.bank.simulation.constant.TableConstants.DETAIL_TABLE_NAME;

/**
 * ClassName CITICAccountServiceImpl
 * Description 中信银行
 *
 * @author Yat
 * Date 2023/5/31 18:10
 * version 1.0
 */
@Slf4j
@Service
@SuppressWarnings("unchecked")
public class CITICBankMessage extends AbstractBankMessage {

    @Override
    public String bankCode() {
        return BankEnum.CITIC.name();
    }


    @Override
    public String getActionName(String message) {
        Document document = XmlUtil.readXML(message.trim());
        // 获取接口名称
        return Convert.toStr(
                XmlUtil.getByXPath("//stream/action", document, XPathConstants.STRING)
        );
    }

    @Override
    protected String getType(String actionName) {

        ArrayList<String> query = ListUtil.toList(
                DLBALQRY, DLTRNALL, DLCIDBST, DLUPRDET, DLCIDSTT,
                DLSALDET, DLEDDRSQ, DLEDCDTD
        );

        ArrayList<String> pay = ListUtil.toList(DLINTTRN, DLUPRSUB, DLSALIMP);

        if (query.contains(actionName)) {
            return InterfaceTypeEnum.query.getValue();
        } else if (pay.contains(actionName)) {
            return InterfaceTypeEnum.trade.getValue();
        }
        return null;

    }

    @Override
    public String inlet(String message) {
        Map<String, Object> xmlToMap = XmlUtil.xmlToMap(message.trim());

        // 获取接口名称
        String action = Convert.toStr(xmlToMap.get("action"));

        action = action.replaceAll("\r|\n", "").trim();
        return switch (action) {
            case DLBALQRY -> queryBalance(xmlToMap);
            case DLTRNALL -> queryDetail(xmlToMap);
            case DLINTTRN -> b2BPay(xmlToMap);
            case DLCIDBST -> b2BPayQuery(xmlToMap);
            case DLUPRSUB -> b2cPay(xmlToMap);
            case DLUPRDET, DLCIDSTT -> b2cPayQuery(xmlToMap);
            case DLSALIMP -> payRoll(xmlToMap);
            case DLSALDET -> payRollQuery(xmlToMap);
            case DLEDDRSQ -> queryReceiptInfo(xmlToMap);
            case DLEDCDTD -> dowReceipt(xmlToMap);
            default -> action;
        };

    }

    @Override
    @SneakyThrows
    public R<Dict> queryDetail(Dict jsonObject) {

        // 账户
        String account = jsonObject.getStr("account");
        // 最小金额
        BigDecimal lowAmount = jsonObject.getBigDecimal("lowAmount");
        // 最大金额
        BigDecimal upAmount = jsonObject.getBigDecimal("upAmount");
        // 起始日期
        String startDate = jsonObject.getStr("startDate");
        // if (StrUtil.isNotBlank(startDate)) {
        //     startDate = DateUtil.format(DateUtil.parse(startDate), DatePattern.PURE_DATE_PATTERN);
        // }
        // 终止日期
        String endDate = jsonObject.getStr("endDate");
        // if (StrUtil.isNotBlank(endDate)) {
        //     endDate = DateUtil.format(DateUtil.parse(endDate), DatePattern.PURE_DATE_PATTERN);
        // }

        // 请求记录条数，最大为20
        int pageNumber = jsonObject.get("pageNumber", 20);
        // 起始记录号
        int startRecord = jsonObject.get("startRecord", 0);
        if (startRecord != 0) {
            startRecord = startRecord / 20;
        }


        // 控制标签char(1)，0：客户系统不兼容银行端新增返回字；1：客户系统兼容银行端新增返回字段；2：客户系统兼容银行端返回新增原始流水字段，标签可空；
        // String controlFlag = jsonObject.getStr("controlFlag");


        SqlBuilder builder = getSqlBuilder(account, lowAmount, upAmount, startDate, endDate);

        Page requestPage = getRequestPage(startRecord, pageNumber);

        PageResult<Entity> page = page(builder.build(), requestPage, Entity.class, builder.getParamValueArray());

        long count = page.getTotal();

        Dict dict = new Dict();
        dict.put("count", count);

        if (count == 0) {
            dict.put("data", ListUtil.toList());
            return R.ok(dict);
        }

        List<Dict> list = DataUtil.toCamelCase(page);

        if (list.isEmpty()) {
            dict.put("count", 0);
        }

        dict.put("data", list);

        return R.ok(dict);
    }

    /**
     * 查询电子回单
     *
     * @param queryReceipt 查询电子回单的参数
     */
    private R<ResponseReceiptDTO> queryReceipt(QueryReceiptDTO queryReceipt) {

        // 账号
        String accNo = queryReceipt.getAccNo();
        // 0：全部；1：转账类；2：利息类；3：收费类；4：电子缴税；5：网银结售汇；6：现金管理转账
        String billType = queryReceipt.getBillType();

        BigDecimal maxAmt = queryReceipt.getMaxAmt();
        BigDecimal minAmt = queryReceipt.getMinAmt();

        String startDate = queryReceipt.getStartDate();
        String endDate = queryReceipt.getEndDate();

        // 起始
        String startNo = queryReceipt.getStartNo();

        SqlBuilder builder = SqlBuilder.create().select("*").from(DETAIL_TABLE_NAME)
                .where("status = 1")
                .append(" and bank_code = '" + bankCode()+"'")
                .append(" and account_no = " + accNo);

        if (ObjectUtil.isNotNull(minAmt)) {
            builder.append(" and money >=" + minAmt);
        }
        if (ObjectUtil.isNotNull(maxAmt)) {
            builder.append(" and money <=" + maxAmt);
        }
        if (CharSequenceUtil.isNotBlank(startDate)) {
            builder.append(" and tran_date >=" + startDate);
        }
        if (CharSequenceUtil.isNotBlank(endDate)) {
            builder.append(" and tran_date <=" + endDate);
        }
        if (CharSequenceUtil.isNotBlank(startNo)) {
            builder.append(" and id >=" + startNo);
        }
        if (CharSequenceUtil.isNotBlank(billType)) {
            builder.append(" and type =" + billType);
        }

        try {
            List<Entity> query = db.query(builder.build());

            ResponseReceiptDTO dict = new ResponseReceiptDTO();
            dict.setData(query);

            return R.ok(dict);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public String prohibitAccess(String body) {
        return "<?xml version=\"1.0\" encoding=\"GBK\"?>  " +
               "<stream>  " +
               "<status>ED02100</status>  " +
               "<statusText>" + body + "</statusText>  " +
               "<list name=\"userDataList\"></list>  " +
               "</stream>";
    }

    @Override
    public R<Dict> dowReceipt(List<ReceiptDTO> receiptList) {
        Set<String> idSet = receiptList.stream().map(ReceiptDTO::getBrSeqNo).collect(Collectors.toSet());

        List<Entity> entityList = detailService.getDetailById(idSet);

        if (entityList.isEmpty()) {
            return R.failed("回单编号错误");
        }

        File mkdir = FileUtil.mkdir("/tmp/sklf/citic/" + IdUtil.getSnowflakeNextIdStr() + "0/");

        for (Entity entity : entityList) {
            String id = entity.getStr("id");
            // entity.set("fileName", id);

            String pdfPath = detailService.createPdf(entity);
            log.info("转换完成的PDF文件----------->" + pdfPath);

            Path source = Paths.get(pdfPath);
            Path destination = Paths.get(mkdir + "/" + id + ".pdf");
            try {
                Files.copy(source, destination);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        File zip = ZipUtil.zip(mkdir);
        String zipName = zip.getName();

        byte[] bytesByFile = PdfUtil.getBytesByFile(zip.getPath());

        String encodeStr = Base64.encodeStr(bytesByFile, true, false);

        Dict dict = new Dict();
        dict.set("fileConTent", encodeStr);
        dict.set("fileName", zipName);

        // 删除临时PDF文件
        // FileUtil.del(pdfPath);

        return R.ok(dict);
    }


    /**
     * 查余额
     */
    private String queryBalance(Map<String, Object> xmlToMap) {
        CiticQueryBalanceDTO queryBalance = BeanUtil.toBean(xmlToMap, CiticQueryBalanceDTO.class);

        // 获取账号
        String account = queryBalance.getList().getRow().get(0).getAccountNo();

        R<Dict> data = queryBalance(account);
        if (data.getCode() == CodeConstants.ERROR) {
            return error(data.getMsg());
        }
        return queryBalanceResponse(account, data.getData());
    }


    private String queryBalanceResponse(String accountNo, Dict data) {
        return "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
               "<stream>" +
               "    <status>AAAAAAA</status>" +
               "    <statusText>交易成功</statusText>" +
               "    <list name=\"userDataList\">" +
               "        <row>" +
               "            <accountName>" + data.getStr("accountName") + "</accountName>" +
               "            <accountNo>" + accountNo + "</accountNo>" +
               "            <balance>" + data.getBigDecimal("money") + "</balance>" +
               "            <currencyID>01</currencyID>" +
               "            <forzenAmt>0.00</forzenAmt>" +
               "            <lastTranDate>20230418</lastTranDate>" +
               "            <openBankName>" + data.getStr("openBankName") + "</openBankName>" +
               "            <status>AAAAAAA</status>" +
               "            <statusText>交易成功</statusText>" +
               "            <usableBalance>" + data.getBigDecimal("money") + "</usableBalance>" +
               "        </row>" +
               "    </list>" +
               "</stream>";
    }


    /**
     * 查明细，流水
     */
    private String queryDetail(Map<String, Object> xmlToMap) {
        CiticQueryDetailDTO queryDetail = BeanUtil.toBean(xmlToMap, CiticQueryDetailDTO.class);

        // 账户
        String account = queryDetail.getAccountNo();
        // 最小金额
        BigDecimal lowAmount = queryDetail.getLowAmount();
        // 最大金额
        BigDecimal upAmount = queryDetail.getUpAmount();
        // 起始日期
        String startDate = queryDetail.getStartDate();
        // 终止日期
        String endDate = queryDetail.getEndDate();
        // 请求记录条数，最大为20
        int pageNumber = queryDetail.getPageNumber();
        // 起始记录号
        int startRecord = queryDetail.getStartRecord();
        // 控制标签char(1)，0：客户系统不兼容银行端新增返回字；1：客户系统兼容银行端新增返回字段；2：客户系统兼容银行端返回新增原始流水字段，标签可空；
        String controlFlag = queryDetail.getControlFlag();

        if (StrUtil.isBlankIfStr(account)) {
            return error("账号不能为空");
        }

        if (pageNumber == 0) {
            pageNumber = 20;
        }
        if (pageNumber > 20) {
            return error("每页最多显示20条记录");
        }

        Dict dict = new Dict();

        dict.set("account", account);
        dict.set("lowAmount", lowAmount);
        dict.set("upAmount", upAmount);
        dict.set("startDate", startDate);
        dict.set("endDate", endDate);
        dict.set("pageNumber", pageNumber);
        dict.set("startRecord", startRecord);
        dict.set("controlFlag", controlFlag);

        Dict data = queryDetail(dict).getData();

        int count = data.getInt("count");
        if (count == 0) {
            return "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
                   "<stream>" +
                   " <returnRecords>" + count + "</returnRecords>" +
                   " <status>AAAAAAA</status>" +
                   " <statusText>交易成功</statusText>" +
                   " <totalRecords>" + count + "</totalRecords>" +
                   " <list name=\"userDataList\"></list>" +
                   "</stream>";
        }
        List<Dict> list = (List<Dict>) data.get("data");
        // return toJson(data)
        return queryDetailResponse(account, list, count);
    }

    private String queryDetailResponse(String accountNo, List<Dict> list, int count) {

        Dict obj = list.get(0);

        return "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
               "<stream>" +
               " <accountName>" + obj.get("accountName") + "</accountName>" +
               " <accountNo>" + accountNo + "</accountNo>" +
               " <openBankName>" + obj.get("bankName") + "</openBankName>" +
               " <returnRecords>" + list.size() + "</returnRecords>" +
               " <status>AAAAAAA</status>" +
               " <statusText>交易成功</statusText>" +
               " <totalRecords>" + count + "</totalRecords>" +
               " <list name=\"userDataList\">" + getRow(list) + " </list>" +
               "</stream>";
    }

    private String getRow(List<Dict> list) {
        StringBuilder xml = new StringBuilder();
        for (Dict dict : list) {
            xml.append("<row>" + "   <abstract>").append(dict.get("postScript")).append("</abstract>").append("   <balance>").append(dict.get("balance")).append("</balance>").append("   <cashTransferFlag>1</cashTransferFlag>").append("   <chkNum></chkNum>").append("   <ckId></ckId>").append("   <ckName></ckName>").append("   <creditDebitFlag>").append(dict.get("flag")).append("</creditDebitFlag>").append("   <e3rtDate></e3rtDate>").append("   <e3rtFlag>1</e3rtFlag>").append("   <hostTranCode>1001045</hostTranCode>").append("   <hostTranDesc>").append(dict.get("summary")).append("</hostTranDesc>").append("   <opId></opId>").append("   <opName></opName>").append("   <oppAccountName>").append(dict.get("oppAccountName")).append("</oppAccountName>").append("   <oppAccountNo>").append(dict.get("oppAccountNo")).append("</oppAccountNo>").append("   <oppOpenBankName>").append(dict.get("oppBankName")).append("</oppOpenBankName>").append("   <rfTranDt></rfTranDt>").append("   <rfTranNo></rfTranNo>").append("   <rlTranNo></rlTranNo>").append("   <subAcccNo></subAcccNo>").append("   <sumTranNo>").append(dict.get("batchSerialNo")).append("</sumTranNo>").append("   <tranAmount>").append(dict.get("money")).append("</tranAmount>").append("   <tranDate>").append(dict.get("tranDate")).append("</tranDate>").append("   <tranNo>").append(dict.get("serialNo")).append("</tranNo>").append("   <tranTime>").append(dict.get("tranTime")).append("</tranTime>").append("   <valueDate>20230418</valueDate>").append("  </row>");
        }

        return xml.toString();
    }

    /**
     * 对公支付
     */
    private String b2BPay(Map<String, Object> xmlToMap) {

        HashMap<String, String> mapping = new HashMap<>();
        mapping.put("abstract", "abstractX");
        CopyOptions copyOptions = CopyOptions.create().setFieldMapping(mapping);

        CiticB2bPayDTO citicB2BPayDTO = BeanUtil.toBean(xmlToMap, CiticB2bPayDTO.class, copyOptions);

        List<TransferPaymentDTO> array = new ArrayList<>();
        List<CiticB2bPayDTO.ListDTO.RowDTO> row = citicB2BPayDTO.getList().getRow();

        String snowflakeNextIdStr = IdUtil.getSnowflakeNextIdStr();

        for (CiticB2bPayDTO.ListDTO.RowDTO rowDTO : row) {

            // 客户流水号
            String serialNo = rowDTO.getClientID();
            // -支付方式 1：跨行转账；2：行内；3：企业内部转账
            String payFlg = rowDTO.getPayFlg();

            // -付款账号
            String payAccountNo = rowDTO.getPayAccountNo();
            // --收款账号
            String recAccountNo = rowDTO.getRecAccountNo();
            // -收款账号名称
            String recAccountName = rowDTO.getRecAccountName();
            // -收款账号开户行名称
            String recOpenBankName = rowDTO.getRecOpenBankName();
            // -收款账号开户行 当payType为1(跨行转账)时，收款账号开户行名与收款账号开户行联行网点号至少输一项
            String recOpenBankCode = rowDTO.getRecOpenBankCode();
            // -金额
            BigDecimal money = rowDTO.getTranAmount();
            // -附言
            String postScript = rowDTO.getAbstractX();
            // -备注
            String summary = rowDTO.getMemo();

            TransferPaymentDTO dto = new TransferPaymentDTO();

            dto.setSerialNo(serialNo);
            dto.setBatchSerialNo(snowflakeNextIdStr);
            dto.setPayFlg(payFlg);

            dto.setPayAccountNo(payAccountNo);
            dto.setRecAccountNo(recAccountNo);
            dto.setRecAccountName(recAccountName);
            dto.setRecOpenBankCode(recOpenBankCode);
            dto.setRecOpenBankName(recOpenBankName);
            dto.setMoney(money);
            dto.setPostScript(postScript);
            dto.setSummary(summary);
            dto.setBankCode(bankCode());

            array.add(dto);
        }
        R<Dict> dictR = tradingEntrance(array);
        if (dictR.getCode() != CodeConstants.SUCCESS) {
            return error(dictR.getMsg());
        }
        Dict dict = dictR.getData();

        // 成功的交易
        List<Dict> success = (List<Dict>) dict.get("success");

        // 失败的交易
        List<Dict> error = (List<Dict>) dict.get("error");

        return b2BPayResponse(success, error);
    }

    private String b2BPayResponse(List<Dict> success, List<Dict> error) {

        return "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
               "<stream>" +
               " <errTotalAmt>" + b2BPayMoney(error) + "</errTotalAmt>" +
               " <errTotalNum>" + error.size() + "</errTotalNum>" +
               " <status>AAAAAAA</status>" +
               " <statusText>交易成功</statusText>" +
               " <sucTotalAmt>" + b2BPayMoney(success) + "</sucTotalAmt>" +
               " <sucTotalNum>" + success.size() + "</sucTotalNum>" +
               " <list name=\"userDataList\">" + b2BPayRow(success) + b2BPayRow(error) + " </list>" +
               "</stream>";
    }

    private BigDecimal b2BPayMoney(List<Dict> list) {
        BigDecimal money = new BigDecimal("0");
        for (Dict dict : list) {
            BigDecimal decimal = dict.getBigDecimal("money");
            money = NumberUtil.add(decimal, money);
        }
        return money;
    }

    private String b2BPayRow(List<Dict> list) {
        StringBuilder xml = new StringBuilder();

        for (Dict dict : list) {
            String status;
            String statusText;
            int stt;
            if (dict.getInt("status") == 1) {
                status = "AAAAAAA";
                stt = 0;
                statusText = "交易成功";
            } else if (dict.getInt("status") == 0) {
                status = "CCCCCCC";
                statusText = "交易处理中";
                stt = 2;
            } else {
                stt = 1;
                status = "ED02093";
                statusText = dict.get("message", "交易失败");
            }
            xml.append("<row>")
                    .append("   <status>").append(status).append("</status>")
                    .append(" <stt>").append(stt).append("</stt>")
                    .append("   <statusText>").append(statusText).append("</statusText>")
                    .append("   <clientID>").append(dict.getStr("serialNo")).append("</clientID>")
                    .append("  </row>");
        }

        return xml.toString();
    }

    /**
     * 对公查询
     */
    @SneakyThrows
    private String b2BPayQuery(Map<String, Object> xmlToMap) {

        CiticB2bPayQueryDTO b2bPayQuery = BeanUtil.toBean(xmlToMap, CiticB2bPayQueryDTO.class);
        List<String> array = new ArrayList<>();

        List<CiticB2bPayQueryDTO.ListDTO.RowDTO> row = b2bPayQuery.getList().getRow();
        for (CiticB2bPayQueryDTO.ListDTO.RowDTO rowDTO : row) {
            // 客户流水号
            String serialNo = rowDTO.getClientID();
            array.add(serialNo);
        }

        Entity entity = Entity.create(DETAIL_TABLE_NAME);
        entity.set("flag", "D");
        entity.set("serial_no", array);

        List<Entity> data = db.find(entity);

        StringBuilder xml = new StringBuilder()
                .append("<?xml version=\"1.0\" encoding=\"GBK\"?>")
                .append("<stream>")
                .append("  <status>AAAAAAA</status>")
                .append("  <statusText>交易成功</statusText>")
                .append("<list name=\"userDataList\">");

        for (Dict dict : data) {
            String status;
            String statusText;
            int stt;
            if (dict.get("status", -1) == 0) {
                status = "CCCCCCC";
                statusText = "交易处理中";
                stt = 2;
            } else if (dict.get("status", -1) == 1) {
                status = "AAAAAAA";
                statusText = "交易成功";
                stt = 0;
            } else {
                stt = 1;
                status = "ED02093";
                statusText = dict.get("statusText", "交易失败");
            }

            xml.append("<row>")
                    .append(" <qryStatus></qryStatus>")
                    .append(" <qryStatusText></qryStatusText>")
                    .append(" <clientID>").append(dict.getStr("serial_no")).append("</clientID>")
                    .append(" <stt>").append(stt).append("</stt>")
                    // <!--状态标志 char(1)  0：成功；1：失败；2：未知；3：审核拒绝； 4：用户撤销-->
                    .append(" <status>").append(status).append("</status>")
                    .append(" <statusText>").append(statusText).append("</statusText>")
                    .append("</row>");
        }

        return xml + "</list> </stream>";
    }

    /**
     * 对私支付
     */
    private String b2cPay(Map<String, Object> xmlToMap) {

        List<TransferPaymentDTO> array = new ArrayList<>();

        HashMap<String, String> mapping = new HashMap<>();
        mapping.put("abstract", "abstractX");
        CopyOptions copyOptions = CopyOptions.create().setFieldMapping(mapping);

        CiticB2cPayDTO b2cPay = BeanUtil.toBean(xmlToMap, CiticB2cPayDTO.class, copyOptions);

        // 客户流水号
        String batchSerialNo = b2cPay.getClientID();
        // -付款账号
        String payAccountNo = b2cPay.getPayAccountNo();

        List<CiticB2cPayDTO.ListDTO.RowDTO> row = b2cPay.getList().getRow();

        for (CiticB2cPayDTO.ListDTO.RowDTO rowDTO : row) {

            // 客户流水号
            String serialNo = rowDTO.getId();
            // --收款账号
            String recAccountNo = rowDTO.getRecAccountNo();
            // -收款账号名称
            String recAccountName = rowDTO.getRecAccountName();
            // -收款账号开户行 当payType为1(跨行转账)时，收款账号开户行名与收款账号开户行联行网点号至少输一项
            String recOpenBankCode = rowDTO.getRecBankCode();
            // -金额
            BigDecimal money = rowDTO.getTranAmount();
            // -附言
            String postScript = rowDTO.getAbstractX();

            String summary = "对私付款";

            TransferPaymentDTO dto = new TransferPaymentDTO();

            dto.setSerialNo(serialNo);
            dto.setSummary(summary);
            dto.setPayAccountNo(payAccountNo);
            dto.setRecAccountNo(recAccountNo);
            dto.setRecAccountName(recAccountName);
            dto.setRecOpenBankCode(recOpenBankCode);
            dto.setBatchSerialNo(batchSerialNo);
            dto.setMoney(money);
            dto.setPostScript(postScript);
            dto.setSummary(summary);
            dto.setBankCode(bankCode());

            array.add(dto);

        }
        tradingEntrance(array);

        return "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
               "<stream><status>AAAAAAA</status><statusText>交易成功</statusText></stream>";
    }

    /**
     * 对私查询
     */
    private String b2cPayQuery(Map<String, Object> xmlToMap) {
        CiticB2cPayQueryDTO b2cPayQuery = BeanUtil.toBean(xmlToMap, CiticB2cPayQueryDTO.class);

        // 客户流水号
        String clientID = b2cPayQuery.getClientID();

        SqlBuilder builder = SqlBuilder.create().select("*").from(DETAIL_TABLE_NAME)
                .where("batch_serial_no = " + clientID)
                .append(" and flag ='D' ");

        List<Dict> data = query(builder.build());

        if (data.size() == 0) {
            SqlBuilder sqlBuilder = SqlBuilder.create().select("*").from(DETAIL_TABLE_NAME)
                    .where("serial_no = " + clientID)
                    .append(" and flag ='D' ");

            data = query(sqlBuilder.build());
            if (data.size() == 0) {
                return error("该笔订单不存在");
            }
        }
        String payAccountNo = data.get(0).getStr("accountNo");
        BigDecimal successAmount = new BigDecimal("0.00");
        int succNum = 0;
        String postScript = data.get(0).getStr("postScript");

        BigDecimal failAmount = new BigDecimal("0.00");
        int failNum = 0;

        StringBuilder rowXml = new StringBuilder();

        for (Dict dict : data) {
            String status;
            String statusText;

            BigDecimal money = dict.get("money", new BigDecimal("0.00"));
            Integer objInt = dict.get("status", -1);

            int stt;
            switch (objInt) {
                case 0 -> {
                    failNum += 1;
                    failAmount = NumberUtil.add(money, failAmount);
                    status = "CCCCCCC";
                    stt = 2;
                    statusText = "交易处理中";
                }
                case 1 -> {
                    succNum += 1;
                    successAmount = NumberUtil.add(money, successAmount);
                    status = "AAAAAAA";
                    stt = 0;
                    statusText = "交易成功";
                }
                default -> {
                    failNum += 1;
                    failAmount = NumberUtil.add(money, failAmount);
                    status = "ED02093";
                    stt = 1;
                    statusText = dict.getStr("statusText");
                }
            }

            rowXml.append("<row>")
                    .append("   <ID>00001</ID>")
                    .append("   <abstract>").append(dict.get("postScript")).append("</abstract>")
                    .append("   <field1></field1>")
                    .append("   <field2></field2>")
                    .append("   <field3></field3>")
                    .append("   <recAccountName>").append(dict.get("oppAccountName")).append("</recAccountName>")
                    .append("   <recAccountNo>").append(dict.get("oppAccountNo")).append("</recAccountNo>")
                    .append("   <status>").append(status).append("</status>")
                    .append("   <statusText>").append(statusText).append("</statusText>")
                    .append(" <stt>").append(stt).append("</stt>")
                    .append("   <tranAmount>").append(money).append("</tranAmount>")
                    .append("</row>");
        }

        return "<?xml version=\"1.0\" encoding=\"GBK\"?>  " +
               "<stream>  " +
               "<abstract>" + postScript + "</abstract>  " +
               "<failAmount>" + failAmount + "</failAmount>  " +
               "<failNum>" + failNum + "</failNum>  " +
               "<payAccountNo>" + payAccountNo + "</payAccountNo>  " +
               "<status>AAAAAAA</status>  " +
               "<statusText>交易成功</statusText>  " +
               "<succAmount>" + successAmount + "</succAmount>  " +
               "<succNum>" + succNum + "</succNum>  " +
               "<list name=\"userDataList\">" + rowXml + "</list>  " +
               "</stream>";
    }

    /**
     * 代发工资
     */
    private String payRoll(Map<String, Object> xmlToMap) {
        HashMap<String, String> mapping = new HashMap<>();
        mapping.put("abstract", "abstractX");
        CopyOptions copyOptions = CopyOptions.create().setFieldMapping(mapping);

        CiticPayRollDTO payRoll = BeanUtil.toBean(xmlToMap, CiticPayRollDTO.class, copyOptions);


        List<TransferPaymentDTO> array = new ArrayList<>();

        // 总金额
        BigDecimal totalAmount = payRoll.getTotalAmount();

        // 客户流水号
        String batchSerialNo = payRoll.getClientID();
        // -付款账号
        String payAccountNo = payRoll.getPayAccountNo();
        // -附言
        String postScript = payRoll.getAbstractX();
        // -工资代发时间
        String additional = payRoll.getYearMonth();

        List<CiticPayRollDTO.ListDTO.RowDTO> row = payRoll.getList().getRow();
        for (CiticPayRollDTO.ListDTO.RowDTO rowDTO : row) {

            // 客户流水号
            String serialNo = rowDTO.getEmployeeNo();
            // --收款账号
            String recAccountNo = rowDTO.getRecAccountNo();
            // -收款账号名称
            String recAccountName = rowDTO.getEmployeeName();
            // -金额
            BigDecimal money = rowDTO.getTranAmount();

            String summary = "代发工资";

            TransferPaymentDTO dto = new TransferPaymentDTO();

            dto.setSerialNo(serialNo);
            dto.setSummary(summary);
            dto.setPayAccountNo(payAccountNo);
            dto.setRecAccountNo(recAccountNo);
            dto.setRecAccountName(recAccountName);
            dto.setAdditional(additional);
            dto.setBatchSerialNo(batchSerialNo);
            dto.setMoney(money);
            dto.setPostScript(postScript);
            dto.setSummary(summary);
            dto.setBankCode(bankCode());

            array.add(dto);
        }

        tradingEntrance(array);

        return "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
               "<stream>" +
               "  <batchNo>1</batchNo>" +
               "  <preDate></preDate>" +
               "  <preFlag>0</preFlag>" +
               "  <preTime></preTime>" +
               "  <status>AAAAAAA</status>" +
               "  <statusText>交易成功</statusText>" +
               "  <totalAmount>" + totalAmount + "</totalAmount>" +
               "  <totalNumber>" + row.size() + "</totalNumber>" +
               "</stream>";
    }

    /**
     * 代发工资查询
     */
    private String payRollQuery(Map<String, Object> xmlToMap) {
        CiticPayRollQueryDTO payRollQuery = BeanUtil.toBean(xmlToMap, CiticPayRollQueryDTO.class);

        // -工资代发的批量流水号
        String clientID = payRollQuery.getClientID();

        SqlBuilder builder = SqlBuilder.create().select("*").from("detail")
                .where(" batch_serial_no=  " + clientID)
                .append(" and flag = 'D' ");

        List<Dict> data = query(builder.build());

        if (data.size() == 0) {
            return error("该笔订单不存在");
        }

        StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"GBK\"?>" +
                                              "<stream>" +
                                              "<status>AAAAAAA</status>" +
                                              "<statusText>交易成功</statusText>" +
                                              "<payAccountNo>" + data.get(0).getStr("accountNo") + "</payAccountNo>" +
                                              "<returnRecords>" + data.size() + "</returnRecords>" +
                                              "<totalRecords>" + data.size() + "</totalRecords>" +
                                              "<chkNum></chkNum>" +
                                              "<list name=\"userDataList\">");

        for (Dict obj : data) {
            Integer objInt = obj.getInt("status");

            String status;
            String statusText;
            if (objInt == 0) {
                status = "CCCCCCC";
                statusText = "交易处理中";
            } else if (objInt == 1) {
                status = "AAAAAAA";
                statusText = "交易成功";
            } else {
                status = "ED02093";
                statusText = obj.getStr("statusText");
            }

            xml.append("<row>")
                    .append("<employeeName>").append(obj.get("oppAccountName")).append("</employeeName>")
                    .append("<employeeNo>").append(obj.getStr("serialNo")).append("</employeeNo>")
                    .append("<recAccountNo>").append(obj.getStr("oppAccountNo")).append("</recAccountNo>")
                    .append("<tranAmount>").append(obj.getBigDecimal("money")).append("</tranAmount>")
                    .append("<status>").append(status).append("</status>")
                    .append("<statusText>").append(statusText).append("</statusText>")
                    .append("<wagDetl></wagDetl>")
                    .append("</row>");
        }
        return xml + "</list> </stream>";
    }

    /**
     * 查询回单信息
     */
    private String queryReceiptInfo(Map<String, Object> xmlToMap) {

        CiticQueryReceiptInfoDTO queryReceiptInfo = BeanUtil.toBean(xmlToMap, CiticQueryReceiptInfoDTO.class);

        // 账户
        String accNo = queryReceiptInfo.getAccNo();
        // 最小金额
        BigDecimal minAmt = queryReceiptInfo.getMinAmt().equals(new BigDecimal("0")) ?
                null : queryReceiptInfo.getMinAmt();
        // 最大金额
        BigDecimal maxAmt = queryReceiptInfo.getMaxAmt().equals(new BigDecimal("0")) ?
                null : queryReceiptInfo.getMaxAmt();
        // 起始日期
        String startDate = queryReceiptInfo.getStartDate();
        // 终止日期
        String endDate = queryReceiptInfo.getEndDate();
        // 请求记录条数，最大为20
        int pageSize = queryReceiptInfo.getPageSize();
        // 起始记录号
        String startNo = queryReceiptInfo.getStartNo();
        // <!--回单类型char(1)，0：全部；1：转账类；2：利息类；3：收费类；4：电子缴税；5：网银结售汇；6：现金管理转账-->
        String billType = "";

        QueryReceiptDTO queryReceiptDTO = new QueryReceiptDTO();
        queryReceiptDTO.setStartDate(startDate);
        queryReceiptDTO.setEndDate(endDate);
        queryReceiptDTO.setAccNo(accNo);
        queryReceiptDTO.setMaxAmt(maxAmt);
        queryReceiptDTO.setMinAmt(minAmt);
        queryReceiptDTO.setStartNo(startNo);
        queryReceiptDTO.setBillType(billType);
        queryReceiptDTO.setSize(pageSize);

        ResponseReceiptDTO dict = queryReceipt(queryReceiptDTO).getData();

        StringBuilder xml = new StringBuilder()
                .append("<?xml version=\"1.0\" encoding=\"GBK\"?>")
                .append("<stream>")
                .append("<status>AAAAAAA</status>")
                .append("<statusText>交易成功</statusText>")
                .append("<totalCount>").append(dict.getData().size()).append("</totalCount>")
                .append("<list name=\"userDataList\">");

        List<Entity> list = dict.getData();
        for (Entity entity : list) {
            String flag = entity.getStr("flag");
            String payerAccNo = "";
            String payerAccNm = "";
            String payeeAccNo = "";
            String payeeAccNm = "";
            if("D".equals(flag)){
                payeeAccNo = entity.getStr("account_no");
                payeeAccNm = entity.getStr("account_name");
                payerAccNo = entity.getStr("opp_account_no");
                payerAccNm = entity.getStr("opp_account_name");
            }else{
                payerAccNo = entity.getStr("account_no");
                payerAccNm = entity.getStr("account_name");
                payeeAccNo = entity.getStr("opp_account_no");
                payeeAccNm = entity.getStr("opp_account_name");
            }
            xml.append("<row>")
                    .append("<tranDate>").append(entity.get("additional", "")).append("</tranDate>")
                    .append("<transeqNo>").append(entity.get("serial_no")).append("</transeqNo>")
                    .append("<brseqNo>").append(entity.get("id")).append("</brseqNo>")
                    .append("<billType>").append("400001").append("</billType>")
                    .append("<tranDate>").append(entity.get("tran_date")).append("</tranDate>")
                    .append("<tranAmt>").append(entity.get("money")).append("</tranAmt>")
                    .append("<cdfg>").append(entity.get("flag")).append("</cdfg>")
                    .append("<payerAccNo>").append(payerAccNo).append("</payerAccNo>")
                    .append("<payerAccNm>").append(payerAccNm).append("</payerAccNm>")
                    .append("<payeeAccNo>").append(payeeAccNo).append("</payeeAccNo>")
                    .append("<payeeAccNm>").append(payeeAccNm).append("</payeeAccNm>")
                    .append("</row>");
        }

        return xml + "</list></stream>";
    }

    /**
     * 下载回单
     */
    private String dowReceipt(Map<String, Object> xmlToMap) {
        List<ReceiptDTO> list = new ArrayList<>();

        CiticDowReceiptDTO dowReceipt = BeanUtil.toBean(xmlToMap, CiticDowReceiptDTO.class);

        List<CiticDowReceiptDTO.ListDTO.RowDTO> row = dowReceipt.getList().getRow();

        for (CiticDowReceiptDTO.ListDTO.RowDTO rowDTO : row) {
            // 回单编号
            String brSeqNo = rowDTO.getBrSeqNo();
            // 回单类型
            String billType = rowDTO.getBillType();

            ReceiptDTO build = ReceiptDTO.builder()
                    .brSeqNo(brSeqNo).billType(billType)
                    .pdfName(brSeqNo + ".pdf").build();

            list.add(build);
        }
        R<Dict> dictR = dowReceipt(list);
        if (dictR.getCode() == 10000) {

            StrBuilder xml = new StrBuilder("<?xml version=\"1.0\" encoding=\"GBK\"?>")
                    .append("<stream>")
                    .append("  <status>AAAAAAA</status>")
                    .append("  <statusText>交易成功</statusText>")
                    .append("  <list name=\"userDataList\">");

            for (ReceiptDTO receiptDTO : list) {
                xml.append("<row>")
                        .append("<brSeqNo>").append(receiptDTO.getBrSeqNo()).append("</brSeqNo>")
                        .append("<billType>").append(receiptDTO.getBillType()).append("</billType>")
                        .append("<pdfName>").append(receiptDTO.getPdfName()).append("</pdfName>")
                        .append("</row>");
            }

            Dict data = dictR.getData();

            xml.append("</list>")
                    .append("<fileConTent>").append(data.getStr("fileConTent")).append("</fileConTent>")
                    .append("<fileName>").append(data.getStr("fileName")).append("</fileName>")
                    .append("<size>").append(String.valueOf(list.size())).append("</size>")
                    .append("</stream>");

            return xml.toString();
        }

        return "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
               "<stream>" +
               "  <status>E2378B</status>" +
               "  <statusText>交易失败</statusText>" +
               "  <list name=\"userDataList\">" +
               "   </list>" +
               "  <fileConTent> </fileConTent>" +
               "  <fileName></fileName>" +
               "  <size></size>" +
               "</stream>";
    }

    /**
     * Description: 错误响应报文模板
     * <p>
     * Date: 2023年6月26日, 0026 17:24
     *
     * @param err 错误信息
     * @return {@link String}
     */
    private String error(String err) {
        return "<?xml version=\"1.0\" encoding=\"GBK\"?>" +
               "<stream>" +
               "<status>ED02093</status>" +
               "<statusText>" + err + "</statusText>" +
               "<list name=\"userDataList\">" +
               "<row></row>" +
               "</list>" +
               "</stream>";
    }

}
